

#pragma once

#include "zdbhatch.h"
#include <tchar.h>

class UcDbCircle;
class UcDb2dPolyline;
class UcDbPolyline;
class UcDbMPolygonCrossingArray;
class UcDbMPolygonNode;

const double UcDbMPolygonCrossingFuzz = 1E-6;

class UcDbMPolygon : public UcDbEntity {
public:

    enum loopDir {
        kExterior     = 0,            
        kInterior,                    
        kAnnotation                   
    };

    UcDbMPolygon();
    virtual ~UcDbMPolygon();

    UCDB_DECLARE_MEMBERS(UcDbMPolygon);

    virtual UcDbHatch * hatch();

    virtual double elevation() const;
    virtual Ucad::ErrorStatus setElevation(double elevation);

    virtual UcGeVector3d normal() const;
    virtual Ucad::ErrorStatus setNormal(const UcGeVector3d& normal);

    virtual Ucad::ErrorStatus  evaluateHatch(bool bUnderestimateNumLines = false);

    virtual UcDbHatch::HatchPatternType patternType() const;

    virtual const TCHAR* patternName() const;

    virtual Ucad::ErrorStatus  setPattern(UcDbHatch::HatchPatternType patType,
                                  const TCHAR* patName);

    virtual double patternAngle() const;
    virtual Ucad::ErrorStatus setPatternAngle(double angle);

    virtual double patternSpace() const;
    virtual Ucad::ErrorStatus setPatternSpace(double space);

    virtual double patternScale() const;
    virtual Ucad::ErrorStatus setPatternScale(double scale);

    virtual bool patternDouble() const;
    virtual Ucad::ErrorStatus setPatternDouble(bool isDouble);

    virtual int numPatternDefinitions() const;
    virtual Ucad::ErrorStatus  getPatternDefinitionAt(int index, 
                                              double& angle,
                                              double& baseX,
                                              double& baseY,
                                              double& offsetX,
                                              double& offsetY,
                                              UcGeDoubleArray& dashes)
                                              const;

    Ucad::ErrorStatus setGradientAngle(double angle);
    Ucad::ErrorStatus setGradientShift( float shiftValue );
	Ucad::ErrorStatus setGradientOneColorMode( ZSoft::Boolean oneColorMode );
    Ucad::ErrorStatus setGradientColors( unsigned int count, 
                                            UcCmColor* colors,
                                            float* values );
    Ucad::ErrorStatus setGradient(UcDbHatch::GradientPatternType gradType,
                                   const TCHAR* gradName);

    virtual UcCmColor patternColor() const;
    virtual Ucad::ErrorStatus setPatternColor(const UcCmColor& pc);

    virtual double getArea() const;
    virtual double getPerimeter() const;

    virtual bool isBalanced() const;

    virtual UcGeVector2d getOffsetVector() const;

    virtual Ucad::ErrorStatus getMPolygonTree(UcDbMPolygonNode*& loopNode) const;
    virtual void deleteMPolygonTree(UcDbMPolygonNode* loopNode) const;

    virtual Ucad::ErrorStatus appendLoopFromBoundary(const UcDbCircle* pCircle,
        bool excludeCrossing = true, double tol = UcDbMPolygonCrossingFuzz);
    virtual Ucad::ErrorStatus appendLoopFromBoundary(const UcDbPolyline* pPoly,
        bool excludeCrossing = true, double tol = UcDbMPolygonCrossingFuzz);
    virtual Ucad::ErrorStatus appendLoopFromBoundary(const UcDb2dPolyline* pPoly,
        bool excludeCrossing = true, double tol = UcDbMPolygonCrossingFuzz);

    virtual int numMPolygonLoops() const;
    virtual Ucad::ErrorStatus getMPolygonLoopAt(int loopIndex, UcGePoint2dArray& vertices,
                                        UcGeDoubleArray& bulges) const;

    virtual Ucad::ErrorStatus insertMPolygonLoopAt(int loopIndex, 
        const UcGePoint2dArray& vertices, const UcGeDoubleArray& bulges, 
        bool excludeCrossing = true, double tol = UcDbMPolygonCrossingFuzz);

    virtual Ucad::ErrorStatus appendMPolygonLoop(const UcGePoint2dArray& vertices, 
        const UcGeDoubleArray& bulges, bool excludeCrossing = true,
        double tol = UcDbMPolygonCrossingFuzz);
    virtual Ucad::ErrorStatus removeMPolygonLoopAt(int loopIndex);

    virtual Ucad::ErrorStatus balanceTree();
    virtual Ucad::ErrorStatus balanceDisplay();

    virtual Ucad::ErrorStatus getLoopDirection(int lindex, UcDbMPolygon::loopDir& dir) const;
    virtual Ucad::ErrorStatus setLoopDirection(int lindex, UcDbMPolygon::loopDir dir);

    virtual Ucad::ErrorStatus getLoopAtGsMarker(int gsMark, int &loop) const;
    virtual void getChildLoops(int curLoop, UcGeIntArray& selectedLoopIndexes) const;
    virtual int getParentLoop(int curLoop) const;
    virtual int getClosestLoopTo(const UcGePoint3d& worldPt) const;

    virtual int isPointInsideMPolygon(const UcGePoint3d& worldPt, UcGeIntArray& loopsArray,
                                      double tol = UcDbMPolygonCrossingFuzz) const;
    virtual bool isPointOnLoopBoundary(const UcGePoint3d& worldPt, int loop, 
                                       double tol = UcDbMPolygonCrossingFuzz) const;

    virtual Ucad::ErrorStatus loopCrossesItself(bool& crosses, bool findAll,
                                        UcDbMPolygonCrossingArray& crossingsArray,
                                        const UcGePoint2dArray& vertexPts, 
                                        const UcGeDoubleArray& vertexBulges, 
                                        double tol = UcDbMPolygonCrossingFuzz) const;

    virtual bool loopCrossesItself(const UcGePoint2dArray& vertexPts, 
                           const UcGeDoubleArray& vertexBulges, 
                           double tol = UcDbMPolygonCrossingFuzz) const;

    virtual Ucad::ErrorStatus loopCrossesMPolygon(bool& crosses, bool findAll,
                                          UcDbMPolygonCrossingArray& crossingsArray,
                                          const UcGePoint2dArray& testVertexPts, 
                                          const UcGeDoubleArray& testVertexBulges, 
                                          double tol = UcDbMPolygonCrossingFuzz) const;

    virtual bool selfCrosses(const UcGePoint2dArray& vertexPts, 
                     const UcGeDoubleArray& vertexBulges,
                     double tol = UcDbMPolygonCrossingFuzz) const;

    virtual bool includesTouchingLoops(double tol = UcDbMPolygonCrossingFuzz) const;

    virtual Ucad::ErrorStatus getClassID( CLSID* pClsid) const;

    virtual ZSoft::Boolean    worldDraw(UcGiWorldDraw*  mode);
    virtual void              saveAs(UcGiWorldDraw* mode, UcDb::SaveType st);

    virtual Ucad::ErrorStatus getSubentPathsAtGsMarker(
        UcDb::SubentType      type,
        ZSoft::GsMarker/*int*/gsMark,
        const UcGePoint3d&    pickPoint,
        const UcGeMatrix3d&   viewXform,
        int&                  numPaths,
        UcDbFullSubentPath*&  subentPaths,
        int                   numInserts = 0,
        UcDbObjectId*         entAndInsertStack 
        = NULL) const;
    
    virtual Ucad::ErrorStatus getGsMarkersAtSubentPath(
        const UcDbFullSubentPath& subPath, 
        UcArray<ZSoft::GsMarker>/*UcDbIntArray*/&         gsMarkers) const;

    virtual UcDbEntity*       subentPtr(const UcDbFullSubentPath& id) const;

    virtual Ucad::ErrorStatus   intersectWith(
        const UcDbEntity*   ent,
        UcDb::Intersect     intType,
        UcGePoint3dArray&      points,
        ZSoft::GsMarker/*int*/                 thisGsMarker  = 0,
        ZSoft::GsMarker/*int*/                 otherGsMarker = 0)
        const;
    
    virtual Ucad::ErrorStatus   intersectWith(
        const UcDbEntity*   ent,
        UcDb::Intersect     intType,
        const UcGePlane&    projPlane,
        UcGePoint3dArray&      points,
        ZSoft::GsMarker/*int*/                 thisGsMarker  = 0,
        ZSoft::GsMarker/*int*/                 otherGsMarker = 0)
        const;

    virtual Ucad::ErrorStatus   getOsnapPoints(
        UcDb::OsnapMode       osnapMode,
        ZSoft::GsMarker/*int*/gsSelectionMark,
        const UcGePoint3d&    pickPoint,
        const UcGePoint3d&    lastPoint,
        const UcGeMatrix3d&   viewXform,
        UcGePoint3dArray&        snapPoints,
        UcDbIntArray&     geomIds) const;

    virtual Ucad::ErrorStatus getGripPoints(UcGePoint3dArray&     gripPoints,
        UcDbIntArray&  osnapModes,
        UcDbIntArray&  geomIds) const;

    virtual Ucad::ErrorStatus moveGripPointsAt(const UcDbIntArray& indices,
        const UcGeVector3d& offset);

    virtual Ucad::ErrorStatus getStretchPoints(UcGePoint3dArray& stretchPoints) const;

    virtual Ucad::ErrorStatus moveStretchPointsAt( const UcDbIntArray& indices,
        const UcGeVector3d& offset);

    virtual Ucad::ErrorStatus   transformBy(const UcGeMatrix3d& xform);
    virtual Ucad::ErrorStatus	getGeomExtents(UcDbExtents& extents) const;
    virtual void              list() const;
    
    virtual Ucad::ErrorStatus   explode( UcDbVoidPtrArray& entitySet) const;

    virtual Ucad::ErrorStatus dwgInFields(UcDbDwgFiler* filer);
    virtual Ucad::ErrorStatus dwgOutFields(UcDbDwgFiler* filer) const;
    virtual Ucad::ErrorStatus dxfInFields(UcDbDxfFiler* filer);
    virtual Ucad::ErrorStatus dxfOutFields(UcDbDxfFiler* filer) const;
    virtual Ucad::ErrorStatus audit(UcDbAuditInfo* );
    virtual Ucad::ErrorStatus decomposeForSave(UcDb::UcDbDwgVersion ver,
        UcDbObject*& replaceObj, UcDbObjectId& replaceId, 
        ZSoft::Boolean& exchangeXData);
    virtual Ucad::ErrorStatus createLoopsFromBoundaries (const UcDbObjectIdArray &ids,
        UcDbIntArray &rejectedObjs,
        bool excludeCrossing = true, double tol = UcDbMPolygonCrossingFuzz);
    virtual Ucad::ErrorStatus createLoops (const UcArray<UcGePoint2dArray,UcArrayObjectCopyReallocator<UcGePoint2dArray> > &vertices,
        const UcArray<UcGeDoubleArray,UcArrayObjectCopyReallocator<UcGeDoubleArray> > &bulges, UcDbIntArray &rejectedObjs,
        bool excludeCrossing = true, double tol = UcDbMPolygonCrossingFuzz);

private:
    friend class UcDbImpMPolygon;
    void* pImp;
};

class UcDbMpolygonLoops {
public:
    UcDbMpolygonLoops(int lindex, int gindex = 0, int gcnt = 0);

    int mLoopIndex;                   
    bool mIsText;                     
    int mGripIndex;                   
    int mGripCount;                   
    UcGePoint2dArray mVertexPoints;    
    UcGeDoubleArray mVertexBulges;
};

inline
UcDbMpolygonLoops::UcDbMpolygonLoops(int lindex, int gindex, int gcnt)
{
    mLoopIndex = lindex;
    mGripIndex = gindex;
    mGripCount = gcnt;
}

class UcDbMPolygonCrossing {
public:
    UcDbMPolygonCrossing();
    ~UcDbMPolygonCrossing();

    int getLoopIndex() const;         
    void setLoopIndex(int index);
    
    int getEdgeIndex() const;         
    void setEdgeIndex(int index);

    UcGePoint2d getCrossingPoint() const; 
    void setCrossingPoint(const UcGePoint2d& pt);

private:
    void* pImp;
};

class UcDbMPolygonCrossingArray {
public:
    ~UcDbMPolygonCrossingArray();

    UcArray<UcDbMPolygonCrossing *> mCrossingArray;
};

inline
UcDbMPolygonCrossingArray::~UcDbMPolygonCrossingArray()
{
    UcDbMPolygonCrossing* pCrossing;
    int numCross = mCrossingArray.length();
    for (int i = numCross - 1; i >= 0; i--) {
        pCrossing = mCrossingArray[i];
        mCrossingArray.removeAt(i);
        if (pCrossing != NULL)
            delete pCrossing;
    }
}

class UcDbMPolygonNode {
public:
    
    UcDbMPolygonNode();

public:
    UcDbMPolygonNode * mParent;
    UcArray<UcDbMPolygonNode*> mChildren;
    int mLoopIndex;                   
};

inline
UcDbMPolygonNode::UcDbMPolygonNode()
    : mLoopIndex(-1), mParent(NULL)
{
}



